#pragma once

#include <sstream>
#include <Poco/Exception.h>
#include <mysqlxx/Types.h>


namespace mysqlxx
{
/// Common exception class for MySQL library. Functions code() and errnum() return error numbers from MySQL, for details see mysqld_error.h
struct Exception : public Poco::Exception
{
    explicit Exception(const std::string & msg, int code = 0) : Poco::Exception(msg, code) {}
    int errnum() const { return code(); }
    const char * name() const noexcept override { return "mysqlxx::Exception"; }
    const char * className() const noexcept override { return "mysqlxx::Exception"; }

    Exception * clone() const override { return new Exception(*this); }
    void rethrow() const override { throw *this; } /// NOLINT(cert-err60-cpp)
};


/// Cannot connect to MySQL server
struct ConnectionFailed : public Exception
{
    explicit ConnectionFailed(const std::string & msg, int code = 0) : Exception(msg, code) {}
    const char * name() const noexcept override { return "mysqlxx::ConnectionFailed"; }
    const char * className() const noexcept override { return "mysqlxx::ConnectionFailed"; }

    ConnectionFailed * clone() const override { return new ConnectionFailed(*this); }
    void rethrow() const override { throw *this; } /// NOLINT(cert-err60-cpp)
};


/// Connection to MySQL server was lost
struct ConnectionLost : public Exception
{
    explicit ConnectionLost(const std::string & msg, int code = 0) : Exception(msg, code) {}
    const char * name() const noexcept override { return "mysqlxx::ConnectionLost"; }
    const char * className() const noexcept override { return "mysqlxx::ConnectionLost"; }

    ConnectionLost * clone() const override { return new ConnectionLost(*this); }
    void rethrow() const override { throw *this; } /// NOLINT(cert-err60-cpp)
};


/// Erroneous query.
struct BadQuery : public Exception
{
    explicit BadQuery(const std::string & msg, int code = 0) : Exception(msg, code) {}
    const char * name() const noexcept override { return "mysqlxx::BadQuery"; }
    const char * className() const noexcept override { return "mysqlxx::BadQuery"; }

    BadQuery * clone() const override { return new BadQuery(*this); }
    void rethrow() const override { throw *this; } /// NOLINT(cert-err60-cpp)
};


/// Value parsing failure
struct CannotParseValue : public Exception
{
    explicit CannotParseValue(const std::string & msg, int code = 0) : Exception(msg, code) {}
    const char * name() const noexcept override { return "mysqlxx::CannotParseValue"; }
    const char * className() const noexcept override { return "mysqlxx::CannotParseValue"; }

    CannotParseValue * clone() const override { return new CannotParseValue(*this); }
    void rethrow() const override { throw *this; } /// NOLINT(cert-err60-cpp)
};


std::string errorMessage(MYSQL * driver, const std::string & query = "");

/// For internal need of library.
void checkError(MYSQL * driver);
[[noreturn]] void onError(MYSQL * driver);

}
